/**
 * 
 */
package com.alstudio.event;

import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

import com.alstudio.utils.log.ALLog;

/**
 * 查找事件订阅类的回调方法
 * @author alonso lee
 *
 */
public class SubscriberCallbackFinder {
	

    private static final int MODIFIERS_IGNORE = Modifier.ABSTRACT | Modifier.STATIC;
    //事件订阅对象的回调方法集合
    private static final Map<String, List<SubscriberCallback>> methodCache = new HashMap<String, List<SubscriberCallback>>();
    //不查找回调方法的事件订阅对象集合
    private static final Map<Class<?>, Class<?>> skipMethodVerificationForClasses = new ConcurrentHashMap<Class<?>, Class<?>>();

    List<SubscriberCallback> findSubscriberCallback(Class<?> subscriberClass, String eventMethodName) {
        String key = subscriberClass.getName() + '.' + eventMethodName;
        List<SubscriberCallback> subscriberCallbacks;
        synchronized (methodCache) {
        	subscriberCallbacks = methodCache.get(key);
        }
        if (subscriberCallbacks != null) {
            return subscriberCallbacks;
        }
        subscriberCallbacks = new ArrayList<SubscriberCallback>();
        //订阅事件对象
        Class<?> clazz = subscriberClass;
        //找到的回调方法
        HashSet<String> eventTypesFound = new HashSet<String>();
        //找到的回调方法和拼装后的字符串
        StringBuilder methodKeyBuilder = new StringBuilder();
        while (clazz != null) {
            String name = clazz.getName();
            if (name.startsWith("java.") || name.startsWith("javax.") || name.startsWith("android.")) {
                // 系统的方法，不管
                break;
            }

            // 循环遍历订阅类的方法，找出回调方法
            Method[] methods = clazz.getMethods();
            for (Method method : methods) {
            	//获取方法名
                String methodName = method.getName();
                //与回调方法名匹配
                if (methodName.startsWith(eventMethodName)) {
                	//获取作用域
                    int modifiers = method.getModifiers();
                    if ((modifiers & Modifier.PUBLIC) != 0 && (modifiers & MODIFIERS_IGNORE) == 0) {
                    	//获取回调方法的参数
                        Class<?>[] parameterTypes = method.getParameterTypes();
                        //不支持一个以上参数的回调
                        if (parameterTypes.length == 1) {
                            String modifierString = methodName.substring(eventMethodName.length());
                            //检查回调方法的后缀
                            ALEventDeliveryThreadMode threadMode;
                            //获取事件回调方法是否指定了事件投递的线程模式。
                            if (modifierString.length() == 0) {
                                threadMode = ALEventDeliveryThreadMode.PostThread;
                            } else if (modifierString.equals("MainThread")) {
                                threadMode = ALEventDeliveryThreadMode.MainThread;
                            } else if (modifierString.equals("BackgroundThread")) {
                                threadMode = ALEventDeliveryThreadMode.BackgroundThread;
                            } else if (modifierString.equals("Async")) {
                                threadMode = ALEventDeliveryThreadMode.Async;
                            } else {
                                if (skipMethodVerificationForClasses.containsKey(clazz)) {
                                    continue;
                                } else {
                                    throw new IllegalArgumentException("Illegal onEvent method, check for typos: " + method);
                                }
                            }
                            //获取回调方法的参数对象类
                            Class<?> eventType = parameterTypes[0];
                            //拼装回调方法和参数。如onALEvent>String。
                            methodKeyBuilder.setLength(0);
                            methodKeyBuilder.append(methodName);
                            methodKeyBuilder.append('>').append(eventType.getName());
                            String methodKey = methodKeyBuilder.toString();
                           	// 完成后，此字符串作为key，加入map中
                            if (eventTypesFound.add(methodKey)) {
                                // Only add if not already found in a sub class
                                subscriberCallbacks.add(new SubscriberCallback(method, threadMode, eventType));
                                ALLog.d(methodKey+"加入map");
                            }
                        }
                    } else if (!skipMethodVerificationForClasses.containsKey(clazz)) {
                        ALLog.d("Skipping method (not public, static or abstract): " + clazz + "."
                                + methodName);
                    }
                }
            }
            clazz = clazz.getSuperclass();
        }
        if (subscriberCallbacks.isEmpty()) {
            throw new IllegalArgumentException("Subscriber " + subscriberClass + " has no public methods called "
                    + eventMethodName);
        } else {
        	//以订阅类名为键值，把订阅类的回调方法集合加入到总的回调方法缓存中
            synchronized (methodCache) {
                methodCache.put(key, subscriberCallbacks);
            }
            return subscriberCallbacks;
        }
    }

    static void clearCaches() {
    	//清楚回调方法缓存
        synchronized (methodCache) {
            methodCache.clear();
        }
    }

    static void skipMethodVerificationFor(Class<?> clazz) {
        if (!methodCache.isEmpty()) {
            throw new IllegalStateException("This method must be called before registering anything");
        }
        skipMethodVerificationForClasses.put(clazz, clazz);
    }

    public static void clearSkipMethodVerifications() {
        skipMethodVerificationForClasses.clear();
    }

	
}
